home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / zmdm_src / rz.c < prev    next >
C/C++ Source or Header  |  1988-06-26  |  28KB  |  1,454 lines

  1. /*
  2.  *                ACKNOWLEDGEMENTS
  3.  *
  4.  *    ZMDM was derived from rz/sz for Unix  posted by 
  5.  *    Chuck Forsberg (...!tektronix!reed!omen!caf ). We
  6.  *    thank him for his excellent code, and for giving
  7.  *    us permission to use and distribute his code and
  8.  *    documentation.
  9.  *
  10.  *    Atari St version by:
  11.  *        Jwahar Bammi
  12.  *            usenet: mandrill!bammi@{decvax,sun}.UUCP
  13.  *            csnet:  bammi@mandrill.ces.CWRU.edu
  14.  *            arpa:   bammi@mandrill.ces.CWRU.edu
  15.  *            CompuServe: 71515,155
  16.  */
  17.  
  18. #include "config.h"
  19. #define RVERSION "rz 1.14 01-15-87"
  20. #define RSTVERSION "rz 1.01 03-07-87"
  21. #define OS    "Unix V7/BSD"
  22.  
  23. /* #define RDEBUG */            /* a lot of debugging garb */
  24.  
  25. /*
  26.  *    ATARI ST series implementation notes:
  27.  *
  28.  *        - the following command line options were removed as they
  29.  *          were either  not applicable to the ST environment or
  30.  *          were not deemed reasonable (by me - ofcourse).
  31.  *            1    Not Applicable here as we have a seperate
  32.  *                serial port.
  33.  *            7    In this day and age? Forget it, get another m/c.
  34.  *            a/b    Ascii/Binary - the receive mode (if not
  35.  *                over-ridden by the sender) is automatically
  36.  *                selected depending on the extention given
  37.  *                in the incoming file name. This idea was
  38.  *                present in earlier rz/sz, i wonder why such
  39.  *                a convenient feature was dropped (Chuck ??).
  40.  *                This feature is relevant to ZMODEM only in rz,
  41.  *                as the sender determines the file mode in
  42.  *                XMODEM/YMODEM transfers.
  43.  *                B    Note that `B' has a special meaning.
  44.  *                Specifying -B will force override to
  45.  *                binary mode for each incoming file. Useful
  46.  *                 when doing St-to-St transfers.
  47.  *            D    There is no /dev/null on the ST's
  48.  *            u    not applicable to TOS. Upper and lower
  49.  *                case file names are the same. All the
  50.  *                applicable routines like uncap() and
  51.  *                IsAnyLower() were zapped.
  52.  *
  53.  *        - The    [-][v]rzCOMMAND style of invocation was dropped
  54.  *          as there is no good way to do pipes without the 
  55.  *          microRtx kernal. All references to Pipe and popen()
  56.  *          were zapped.
  57.  *        - Verbose is always set to 2 by automatically, as we know that
  58.  *          stdout != stderr. This can be overridden
  59.  *          by specifying -q to ensure that Verbose = 0
  60.  *        - The idea of a PUBDIR and Restricted paths in the origonal
  61.  *          code  was dropped totally as it is not applicable
  62.  *          to the single owner ST environment. 1 man 1 machine.
  63.  *        - CRCTABLE is default always, hey we have plenty of memory!.
  64.  *        - LOGFILE renamed to 'rzlog/szlog' as we don't always have
  65.  *          a meaningful environment to pick up TMPDIR from (like when
  66.  *          running from the desktop).
  67.  *            - When a subdirectory in an incoming path name is not
  68.  *          present it is created.
  69.  *        - The file mode transmitted is 0S00 where S is derived from
  70.  *          the Read/Write attribute of the file on the ST
  71.  *        - When a file mode is received, only the owner bits are
  72.  *          are checked. If it was read only (r--) on the Unix sytem
  73.  *          then it is given read only attribute on the ST, read-write
  74.  *          otherwise.
  75.  *        - Of course all the I/O was completely redone on the ST.
  76.  *        - You will find two versions of VARARGS routines like log,
  77.  *          one that takes int args, and the other that takes long
  78.  *          (address) args, since sizeof(int) != sizeof(long)
  79.  *          and sizeof(int) != sizeof(pointer) on the ST.
  80.  *
  81.  *    ST v1.01
  82.  *     added support for 32 bit CRC's for Zmodem ++jrb
  83.  *
  84.  *    ST v1.2
  85.  *     added -B ++jrb
  86.  *     added all the recursive stuff
  87.  *     added remote
  88.  */
  89.         
  90. /*% cc -DNFGVMIN -DCRCTABLE -K -O % -o rz; size rz
  91.  *
  92.  * rz.c By Chuck Forsberg
  93.  *
  94.  *    cc -O rz.c -o rz        USG (3.0) Unix
  95.  *     cc -O -DV7  rz.c -o rz        Unix V7, BSD 2.8 - 4.3
  96.  *
  97.  *    ln rz rb            For either system
  98.  *
  99.  *    ln rz /usr/bin/rzrmail        For remote mail.  Make this the
  100.  *                    login shell. rzrmail then calls
  101.  *                    rmail(1) to deliver mail.
  102.  *
  103.  *        define CRCTABLE to use table driven CRC
  104.  *
  105.  *  Unix is a trademark of Western Electric Company
  106.  *
  107.  * A program for Unix to receive files and commands from computers running
  108.  *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM.
  109.  *  rz uses Unix buffered input to reduce wasted CPU time.
  110.  *
  111.  * Iff the program is invoked by rzCOMMAND, output is piped to 
  112.  * "COMMAND filename"
  113.  *
  114.  *  Some systems (Venix, Coherent, Regulus) may not support tty raw mode
  115.  *  read(2) the same way as Unix. ONEREAD must be defined to force one
  116.  *  character reads for these systems. Added 7-01-84 CAF
  117.  *
  118.  *  Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF 
  119.  *
  120.  *  NFGVMIN Added 1-13-85 CAF for PC-AT Xenix systems where c_cc[VMIN]
  121.  *  doesn't seem to work (even though it compiles without error!).
  122.  *
  123.  *  USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin
  124.  */
  125.  
  126.  
  127. #include "zmdm.h"
  128. #include "common.h"
  129. #include "zmodem.h"
  130.  
  131. static unsigned long SaveIntr;
  132.  
  133. #ifndef Vsync             /* Atari forgot these in osbind.h */
  134. #define Vsync()    xbios(37)
  135. #endif
  136.  
  137. #ifndef Supexec
  138.         /* Some versions of osbind don't define Supexec */
  139. #define Supexec(X) xbios(38,X)
  140. #endif
  141.  
  142. #if (MWC || MANX)
  143. extern FILE  *fopen();
  144. #else
  145. extern FILE  *fopen(), *fopenb();
  146. #endif
  147.  
  148. #ifndef STANDALONE
  149. #define RETURN return
  150. #else
  151. int bibis() {} /* dummy */
  152. #endif 
  153.  
  154. static long start_time;
  155.  
  156. /* called by simulated signal interrupt or terminate to clean things up */
  157. bibi(n)
  158. int n;
  159. {
  160.  
  161.     if (Zmodem)
  162.         zmputs(Attn);
  163.     canit(); mode(0);
  164.     fprintf(STDERR, "\r\nrz: caught signal %d; exiting", n);
  165.     if (fout != -1)
  166.     {
  167.         if (stfclose(fout) != 0)
  168.         {
  169.             fprintf(STDERR, "\r\nfile close ERROR\n");
  170.         }
  171.         fout = (-1);
  172.  
  173.     }
  174.  
  175. #ifdef RDEBUG
  176.     if (logf != (FILE *)NULL)
  177.         fclose(logf);
  178. #endif
  179.     aexit(128+n);
  180. }
  181.  
  182. #ifdef STANDALONE
  183. main(argc, argv)
  184. #else
  185. dorz(argc, argv)
  186. #endif /* STANDALONE */
  187. int argc;
  188. char **argv;
  189. {
  190.     register char *cp;
  191.     register int npats;
  192.     char **patts;
  193.     int exitcode;
  194.  
  195. #ifdef STANDALONE
  196. #ifdef MWC
  197.     extern char *lmalloc();
  198. #endif
  199.  
  200.     /* Set up Dta */
  201.     Fsetdta(&statbuf);
  202.  
  203.     /* Get screen rez */
  204.     rez = Getrez();
  205.     drv_map = Drvmap();
  206.  
  207. #if (MWC || MANX)
  208. #ifndef DYNABUF
  209. #ifdef MWC
  210.     if((bufr = (unsigned char *)lmalloc((unsigned long)BBUFSIZ))
  211.                      == (unsigned char *)NULL)
  212. #else
  213.     if((bufr = (unsigned char *)Malloc((unsigned long)BBUFSIZ))
  214.                      == (unsigned char *)NULL)
  215. #endif
  216. #else
  217.     if((bufr = dalloc()) == (unsigned char *)NULL)
  218. #endif /* DYNABUF */
  219.     {
  220. #ifdef REMOTE
  221.         Bauxws("Sorry, could not allocate enough memory\r\n");
  222. #else
  223.         Bconws("Sorry, could not allocate enough memory\r\n");
  224. #endif
  225.  
  226.         Pterm(4);
  227.     }
  228. #else /* MWC || MANX */
  229. #ifdef DYNABUF
  230.     if((bufr = dalloc()) == (unsigned char *)NULL)
  231.     {
  232. #ifdef REMOTE
  233.         Bauxws("Sorry, could not allocate enough memory\r\n");
  234. #else
  235.         Bconws("Sorry, could not allocate enough memory\r\n");
  236. #endif
  237.         Pterm(5);
  238.     }
  239. #endif /* DYNABUF */
  240. #endif /* MWC || MANX */
  241.  
  242. #ifndef REMOTE
  243.     STDERR = stderr;
  244. #else
  245. #ifndef DLIBS
  246.     if((STDERR = fopen("aux:", "rw")) == (FILE *)NULL)
  247.     {
  248.         Bauxws("Could not Open Aux Stream for Stderr\r\n");
  249.         finish();
  250.     }
  251.     setbuf(STDERR, (char *)NULL);
  252. #else
  253.     STDERR = stdaux;
  254. #endif /* DLIBS */
  255.     
  256. #endif /* REMOTE */
  257.  
  258.     {
  259.         int speed;
  260.         speed = getbaud();
  261.         Baudrate = BAUD_RATE(speed);
  262.         SetIoBuf();
  263.         Rsconf(speed, 0,-1,-1,-1,-1);
  264.         Vsync(); Vsync();
  265.     }
  266.  
  267. #endif /* STANDALONE */
  268.  
  269.     SendType = 0;
  270.     Rxtimeout = 100;
  271.     exitcode = 0;
  272.  
  273.     initz();
  274.  
  275. #ifndef STANDALONE
  276.     chkinvok(argv[0]);     /* if called as  'rb' set flag */
  277. #else
  278.     Progname = "rz";
  279. #endif
  280.  
  281.     npats = 0;
  282.     SaveIntr = Setexc(0x0102, -1L);
  283.     BusErr   = Setexc(2, -1L);
  284.     AddrErr  = Setexc(3, -1L);
  285.     vdebug = 0;
  286.  
  287.     while (--argc)
  288.     {
  289.         cp = *++argv;
  290.         if (*cp == '-')
  291.         {
  292.             while( *++cp)
  293.             {
  294.                 switch(*cp)
  295.                 {
  296.                 case '+':
  297.                     Lzmanag = ZMAPND; break;
  298.                 case 'B':
  299.                     ForceBinary=TRUE; break;
  300.                 case 'c':
  301.                     Crcflg=TRUE; break;
  302.                 case 'p':
  303.                     Lzmanag = ZMPROT;  break;
  304.                 case 'q':
  305.                     Quiet=TRUE; Verbose=0; break;
  306.                 case 't':
  307.                     if (--argc < 1) {
  308.                         rusage();
  309.                         RETURN(1);
  310.                     }
  311.                     Rxtimeout = atoi(*++argv);
  312.                     if (Rxtimeout<10 || Rxtimeout>1000)
  313.                     {
  314.                         rusage();
  315.                         RETURN(1);
  316.                     }
  317.                     break;
  318.                 case 'v':
  319.                     ++Verbose; break;
  320.                 default:
  321.                     rusage();
  322.                     RETURN(1);
  323.                 }
  324.             }
  325.         }
  326.         else if ( !npats && argc>0)
  327.         {
  328.             if (argv[0][0])
  329.             {
  330.                 npats=argc;
  331.                 patts=argv;
  332.             }
  333.         }
  334.     }
  335.  
  336.     if (npats > 1)
  337.     {
  338.         rusage();
  339.         RETURN(1);
  340.     }
  341.  
  342. #ifdef RDEBUG
  343.     if (Verbose > 2)
  344.     {
  345.         if ((logf = fopen(RLOGFILE, "a"))== (FILE *)NULL)
  346.         {
  347.             fprintf(STDERR, "Can't open log file %s\n",RLOGFILE);
  348.             RETURN(0200);
  349.         }
  350.         fprintf(logf, "Progname=%s\n", Progname);
  351.         vdebug = 1;
  352.     }
  353. #endif
  354.  
  355.     if ( !Quiet)
  356.     {
  357.         if (Verbose == 0)
  358.             Verbose = 2;
  359.     }
  360.  
  361.     Setexc(0x0102, bibi);
  362.  
  363.     Setexc(2, buserr);
  364.     Setexc(3, addrerr);
  365.  
  366.     if((exitcode = setjmp(abrtjmp)))
  367.     {
  368.         /* on Contrl-C */
  369.         canit();
  370.         Setexc(2, BusErr);
  371.         Setexc(3, AddrErr);
  372.         Setexc(0x0102, SaveIntr);
  373.         RETURN(exitcode);
  374.     }
  375.     
  376.     if(setjmp(busjmp))
  377.     {
  378.         /* On a bus error - instead of 2 bombs */
  379.         fprintf(STDERR,"\r\nFATAL: Bus Error\n\n");
  380. #ifdef RDEBUG
  381.         if(logf != (FILE *)NULL)
  382.             fclose(logf);
  383. #endif
  384.         if(fout != -1)
  385.         {
  386.             if (stfclose(fout) != 0)
  387.             {
  388.                 fprintf(STDERR, "\r\nfile close ERROR\n");
  389.             }
  390.             fout = (-1);
  391.         }
  392.         canit();
  393.         Setexc(2, BusErr);
  394.         Setexc(3, AddrErr);
  395.         Setexc(0x0102, SaveIntr);
  396.  
  397.         RETURN(2);
  398.     }
  399.  
  400.     if(setjmp(addrjmp))
  401.     {
  402.         /* On address error - instead of 3 bombs */
  403.         fprintf(STDERR,"\r\nFATAL: Address Error\n\n");
  404. #ifdef RDEBUG
  405.         if(logf != (FILE *)NULL)
  406.             fclose(logf);
  407. #endif
  408.         if(fout != -1)
  409.         {
  410.             if (stfclose(fout) != 0)
  411.             {
  412.                 fprintf(STDERR, "\r\nfile close ERROR\n");
  413.             }
  414.             fout = (-1);
  415.         }
  416.         canit();
  417.         Setexc(2, BusErr);
  418.         Setexc(3, AddrErr);
  419.         Setexc(0x0102, SaveIntr);
  420.  
  421.         RETURN(3);
  422.     }
  423.  
  424.     mode(1);
  425.  
  426.     if (wcreceive(npats, patts)==ERROR)
  427.     {
  428.         exitcode=0200;
  429.         canit();
  430.     }
  431.  
  432.     mode(0);
  433.     if (exitcode && !Zmodem)    /* bellow again with all thy might. */
  434.         canit();
  435.  
  436. #ifdef RDEBUG
  437.     if(logf != (FILE *)NULL)
  438.         fclose(logf);
  439. #endif
  440.  
  441.     if(fout != -1)
  442.     {
  443.         if (stfclose(fout) != 0)
  444.         {
  445.             fprintf(STDERR, "\r\nfile close ERROR\n");
  446.         }
  447.         fout = (-1);
  448.     }
  449.     Setexc(2, BusErr);
  450.     Setexc(3, AddrErr);
  451.     Setexc(0x0102, SaveIntr);
  452.  
  453.      RETURN(exitcode); 
  454. }
  455.  
  456. #ifdef STANDALONE
  457. RETURN(n)
  458. int n;
  459. {
  460.     ResetIoBuf();
  461. #if (MWC || MANX)
  462. #ifndef DYNABUF
  463.     free(bufr);
  464. #else
  465.     Mfree(bufr);
  466. #endif
  467. #else
  468. #ifdef DYNABUF
  469.     Mfree(bufr);
  470. #endif
  471. #endif
  472.  
  473.     exit(n);
  474. }
  475. #endif /* STANDALONE */
  476.  
  477. rusage()
  478. {
  479.     fprintf(STDERR,
  480.         "%s for %s by ST Enthusiasts at Case Western Reserve University\n",
  481.           RSTVERSION, STOS);
  482.     fprintf(STDERR, "\tBased on %s for %s by Chuck Forsberg\n\n",
  483.         RVERSION, OS);
  484.  
  485.     fprintf(STDERR,"Usage:    rz [-Bpqtv]        (ZMODEM Batch)\n");
  486.     fprintf(STDERR,"or    rb [-qtv]        (YMODEM Batch)\n");
  487.     fprintf(STDERR,"or    rz [-cqtv] file            (XMODEM or XMODEM-1k)\n");
  488.     fprintf(STDERR,"      -B Force Binary Mode transfers\n");
  489.     fprintf(STDERR,"      -v Verbose more v's give more info\n");
  490.     fprintf(STDERR,"          -q Quiet suppresses verbosity\n");
  491.     fprintf(STDERR,"      -t TIM Change timeout to TIM tenths of seconds\n");
  492.     fprintf(STDERR,"      -c Use 16 bit CRC    (XMODEM)\n");
  493.     fprintf(STDERR,"      -p Protect existing dest. file by skipping\n");
  494.     fprintf(STDERR,"         transfer if the dest. file exists (ZMODEM ONLY)\n\n");
  495.  
  496.  
  497.     if(fout != -1)
  498.     {
  499.         if (stfclose(fout) != 0)
  500.         {
  501.             fprintf(STDERR, "\r\nfile close ERROR\n");
  502.         }
  503.         fout = (-1);
  504.     }
  505.  
  506. #ifdef RDEBUG
  507.     if(logf != (FILE *)NULL)
  508.         fclose(logf);
  509. #endif
  510.  
  511.     return(1);
  512. }
  513.  
  514.  
  515. /*
  516.  * Let's receive something already.
  517.  */
  518. wcreceive(argc, argp)
  519. int argc;
  520. char **argp;
  521. {
  522.     register int c;
  523.  
  524.     if (Batch || argc==0)
  525.     {
  526.         Crcflg=(Wcsmask==0377);
  527.         if ( !Quiet)
  528. #ifndef REMOTE
  529.             fprintf(STDERR, "\n%s: ready (CTRL-C to cancel)\n\n",
  530.                 Progname);
  531. #else
  532.             fprintf(STDERR, "\n%s: ready\n\n",
  533.                 Progname);
  534. #endif
  535.         if (c=tryz())
  536.         {
  537.             if (c == ZCOMPL)
  538.                 return OK;
  539.             if (c == ERROR)
  540.                 goto fubar;
  541.             c = rzfiles();
  542.             if (c)
  543.                 goto fubar;
  544.         }
  545.         else
  546.         {
  547.             for (;;)
  548.             {
  549.                 if (wcrxpn(secbuf)== ERROR)
  550.                     goto fubar;
  551.                 if (secbuf[0]==0)
  552.                     return OK;
  553.                 if (procheader(secbuf) == ERROR)
  554.                     goto fubar;
  555.                 if (wcrx()==ERROR)
  556.                     goto fubar;
  557.             }
  558.         }
  559.     } 
  560.     else
  561.     {
  562.         Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  563.  
  564.         strcpy(Pathname, *argp);
  565. #ifndef REMOTE
  566.         fprintf(STDERR, "\n%s: ready to receive %s (CTRL-C to Cancel)\n\n",
  567.             Progname, Pathname);
  568. #else
  569.         fprintf(STDERR, "\n%s: ready to receive %s\n\n",
  570.             Progname, Pathname);
  571. #endif
  572.  
  573. #ifdef RDEBUG
  574.         if(logf != (FILE *)NULL)
  575.             fprintf(logf, "\nrz: ready to receive %s ", Pathname);
  576. #endif
  577.  
  578.         if((fout = stfopen(Pathname,"w")) <= 0)
  579.             return ERROR;
  580.         if (wcrx()==ERROR)
  581.             goto fubar;
  582.     }
  583.     return OK;
  584.  
  585. fubar:
  586.     canit();
  587.  
  588.     if (fout != -1)
  589.     {
  590.         if (stfclose(fout) != 0)
  591.         {
  592.             fprintf(STDERR, "\r\nfile close ERROR\n");
  593.         }
  594.         fout = (-1);
  595.     }
  596.  
  597.     return ERROR;
  598. }
  599.  
  600.  
  601. /*
  602.  * Fetch a pathname from the other end as a C ctyle ASCIZ string.
  603.  * Length is indeterminate as long as less than Blklen
  604.  * A null string represents no more files (YMODEM)
  605.  */
  606. wcrxpn(rpn)
  607. char *rpn;    /* receive a pathname */
  608. {
  609.     register int c;
  610.  
  611.     PURGELINE;
  612.  
  613. et_tu:
  614.     Firstsec=TRUE;  Eofseen=FALSE;
  615.     sendline(Crcflg?WANTCRC:NAK);
  616.     Lleft=0;    /* Do read next time ... */
  617.     while ((c = wcgetsec(rpn, 100)) != 0)
  618.     {
  619.         llog( "Pathname fetch returned %d\n", c);
  620.         if (c == WCEOT)
  621.         {
  622.             sendline(ACK);
  623.             Lleft=0;    /* Do read next time ... */
  624.             readline(1);
  625.             goto et_tu;
  626.         }
  627.         return ERROR;
  628.     }
  629.     sendline(ACK);
  630.     return OK;
  631. }
  632.  
  633. /*
  634.  * Adapted from CMODEM13.C, written by
  635.  * Jack M. Wierda and Roderick W. Hart
  636.  */
  637.  
  638. wcrx()
  639. {
  640.     register int sectnum, sectcurr;
  641.     register char sendchar;
  642.     int cblklen;            /* bytes to dump this block */
  643.  
  644.     Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
  645.     sendchar=Crcflg?WANTCRC:NAK;
  646.  
  647.     for (;;)
  648.     {
  649.         sendline(sendchar);    /* send it now, we're ready! */
  650.         Lleft=0;    /* Do read next time ... */
  651.         sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
  652.         report(sectcurr);
  653.         if (sectcurr==(sectnum+1 &Wcsmask))
  654.         {
  655.             sectnum++;
  656.             cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
  657.             if (putsec(secbuf, cblklen)==ERROR)
  658.                 return ERROR;
  659.             if ((Bytesleft-=cblklen) < 0)
  660.                 Bytesleft = 0;
  661.             sendchar=ACK;
  662.         }
  663.         else if (sectcurr==(sectnum&Wcsmask))
  664.         {
  665.             log2( "Received dup Sector\n");
  666.             sendchar=ACK;
  667.         }
  668.         else if (sectcurr==WCEOT)
  669.         {
  670.             if (closeit(0L))
  671.                 return ERROR;
  672.             sendline(ACK);
  673.             Lleft=0;    /* Do read next time ... */
  674.             return OK;
  675.         }
  676.         else if (sectcurr==ERROR)
  677.             return ERROR;
  678.         else
  679.         {
  680.             log2( "Sync Error\n");
  681.             return ERROR;
  682.         }
  683.     }
  684. }
  685.  
  686.  
  687. /*
  688.  * Wcgetsec fetches a Ward Christensen type sector.
  689.  * Returns sector number encountered or ERROR if valid sector not received,
  690.  * or CAN CAN received
  691.  * or WCEOT if eot sector
  692.  * time is timeout for first char, set to 4 seconds thereafter
  693.  ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
  694.  *    (Caller must do that when he is good and ready to get next sector)
  695.  */
  696. wcgetsec(rxbuf, maxtime)
  697. char *rxbuf;
  698. int maxtime;
  699. {
  700.     register int checksum, wcj, firstch;
  701.     register unsigned int oldcrc;
  702.     register char *p;
  703.     int sectcurr;
  704.  
  705.     for (Lastrx=errors=0; errors<RETRYMAX; errors++)
  706.     {
  707.  
  708.         if ((firstch=readline(maxtime))==STX)
  709.         {
  710.             Blklen=KSIZE; goto get2;
  711.         }
  712.         if (firstch==SOH)
  713.         {
  714.             Blklen=SECSIZ;
  715. get2:
  716.             sectcurr=readline(1);
  717.             if ((sectcurr+(oldcrc=readline(1)))==Wcsmask)
  718.             {
  719.                 oldcrc=checksum=0;
  720.                 for (p=rxbuf,wcj=Blklen; --wcj>=0; )
  721.                 {
  722.                     if ((firstch=readline(1)) < 0)
  723.                         goto bilge;
  724.                     oldcrc=updcrc(firstch, oldcrc);
  725.                     checksum += (*p++ = firstch);
  726.                 }
  727.                 if ((firstch=readline(1)) < 0)
  728.                     goto bilge;
  729.                 if (Crcflg)
  730.                 {
  731.                     oldcrc=updcrc(firstch, oldcrc);
  732.                     if ((firstch=readline(1)) < 0)
  733.                         goto bilge;
  734.                     oldcrc=updcrc(firstch, oldcrc);
  735.                     if (oldcrc & 0xFFFF)
  736.                         llog("CRC=0%o\n", oldcrc);
  737.                     else
  738.                     {
  739.                         Firstsec=FALSE;
  740.                         return sectcurr;
  741.                     }
  742.                 }
  743.                 else if (((checksum-firstch)&Wcsmask)==0)
  744.                 {
  745.                     Firstsec=FALSE;
  746.                     return sectcurr;
  747.                 }
  748.                 else
  749.                     log2( "Checksum Error\n");
  750.             }
  751.             else
  752.                 log2("Sector number garbled 0%o 0%o\n",
  753.                  sectcurr, oldcrc);
  754.         }
  755.         /* make sure eot really is eot and not just mixmash */
  756.  
  757.         else if (firstch==EOT && Lleft==0)
  758.             return WCEOT;
  759.  
  760.         else if (firstch==CAN)
  761.         {
  762.             if (Lastrx==CAN)
  763.             {
  764.                 log2( "Sender CANcelled\n");
  765.                 return ERROR;
  766.             }
  767.             else
  768.             {
  769.                 Lastrx=CAN;
  770.                 continue;
  771.             }
  772.         }
  773.         else if (firstch==TIMEOUT)
  774.         {
  775.             if (Firstsec)
  776.                 goto humbug;
  777. bilge:
  778.             log2( "Timeout\n");
  779.         }
  780.         else
  781.             llog( "Got 0%o sector header\n", firstch);
  782.  
  783. humbug:
  784.         Lastrx=0;
  785.         while(readline(1)!=TIMEOUT)
  786.             ;
  787.         if (Firstsec)
  788.         {
  789.             sendline(Crcflg?WANTCRC:NAK);
  790.             Lleft=0;    /* Do read next time ... */
  791.         }
  792.         else
  793.         {
  794.             maxtime=40; sendline(NAK);
  795.             Lleft=0;    /* Do read next time ... */
  796.         }
  797.     }
  798.     /* try to stop the bubble machine. */
  799.     canit();
  800.     return ERROR;
  801. }
  802.  
  803.  
  804.  
  805.  
  806. /*
  807.  * Process incoming file information header
  808.  */
  809. procheader(name)
  810. char *name;
  811. {
  812.     register char  *p;
  813.     register int dot;
  814.     char openmode[4];
  815.     extern int strlen();
  816.  
  817.     /* convert to ST style path names */
  818.     for( p = name; *p != '\0'; p++)
  819.     {
  820.         if(*p == '/')
  821.             *p = '\\';
  822.     }
  823.     
  824.     /* pick out the last extention in the filename in each part of path */
  825.     while(p != name)
  826.     {
  827.         dot = 0; p-- ;
  828.         while((p != name) && (*p != '\\'))
  829.         {
  830.             if(*p == '.')
  831.             {
  832.                 if(dot == 0)
  833.                 {
  834.                     dot = 1;
  835.                 }
  836.                 else
  837.                 {
  838.                    /* replace all but the last dot with '_' */
  839.                     *p = '_';
  840.                 }
  841.             }
  842.             p--;
  843.         }
  844.     }
  845.                 
  846.     /* set default parameters and overrides */
  847.     strcpy(openmode,"w");
  848.  
  849.     Thisbinary = isbinary(name);
  850.  
  851.     if (Lzmanag)
  852.         zmanag = Lzmanag;
  853.  
  854.     /*
  855.      *  Process ZMODEM remote file management requests
  856.      */
  857.     if ( zconv == ZCNL)    /* Remote ASCII override */
  858.         Thisbinary = 0;
  859.     if (zconv == ZCBIN)    /* Remote Binary override */
  860.         ++Thisbinary;
  861.     else if (zmanag == ZMAPND)
  862.         strcpy(openmode, "a");
  863.  
  864.     if (ForceBinary == TRUE )    /* local binary force override */
  865.         ++Thisbinary;
  866.  
  867.     /* ZMPROT check for existing file */
  868.     if (zmanag == ZMPROT && existf(name, "r"))
  869.     {
  870.         return ERROR;
  871.     }
  872.  
  873. /* ATARI ST NOTE:
  874.  *    We will not accept rooted paths ie. paths that begin in '\' or '.\'
  875.  *    If the incoming filename is rooted, we skip the beginning
  876.  *    '\'   '.\'  or  '..\'
  877.  */
  878.  
  879.     if( (name[0] == '\\') || (name[0] == '.')  )
  880.     {
  881.         /* skip over the leading stuff */
  882.         if(name[0] == '\\')
  883.             name = &name[1];
  884.         else
  885.         {
  886.             if(name[1] == '.')
  887.                 name = &name[3];  /* Skip the "..\" */
  888.             else
  889.                 name = &name[2];  /* Skip the ".\"  */
  890.         }
  891.     }
  892.  
  893.     /* ST addition, create any dierctories in the path that don't exist */
  894.     if( pathensure(name) == ERROR)
  895.         return ERROR;
  896.  
  897.     Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  898.  
  899.     p = name + 1 + strlen(name);
  900.     if (*p)
  901.     {    /* file coming from Unix or DOS system */
  902.         sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
  903. /* NA to atari
  904.             if (Filemode & UNIXFILE)
  905.                 ++Thisbinary; 
  906. */
  907. #ifndef REMOTE
  908.         if (Verbose)
  909.         {
  910.             fprintf(STDERR,
  911.             "\nIncoming:\n\tName:\t%s\n\tBytes:\t%ld\n\
  912. \tModTime: %ld\n\tMode:\t%o\n\tBufSize: %ld\n\n",
  913.               name, Bytesleft, Modtime, Filemode, (long)BBUFSIZ);
  914.  
  915. #ifdef RDEBUG
  916.             if(logf != (FILE *)NULL)
  917.                 fprintf(logf,  "Incoming: %s %ld %lo %o\n",
  918.                   name, Bytesleft, Modtime, Filemode);
  919. #endif
  920.  
  921.         }
  922. #endif /* REMOTE */
  923.  
  924.     }
  925.     else
  926.     {        /* File coming from CP/M system */
  927.         for (p=name; *p; ++p)        /* change / to _ */
  928.             if ( *p == '/')
  929.                 *p = '_';
  930.  
  931.         if ( *--p == '.')        /* zap trailing period */
  932.             *p = 0;
  933.     }
  934.     
  935.     strcpy(Pathname, name);
  936. #ifndef REMOTE
  937.     if (Verbose)
  938.     {
  939.         fprintf(STDERR,  "Receiving %s %s [mode %s]\n\n",
  940.           name, Thisbinary?"BIN":"ASCII", openmode);
  941.  
  942. #ifdef RDEBUG
  943.         if(logf != (FILE *)NULL)
  944.             fprintf(logf,  "Receiving %s %s %s\n",
  945.               name, Thisbinary?"BIN":"ASCII", openmode);
  946. #endif
  947.  
  948.     }
  949. #endif /* REMOTE */
  950.  
  951.     if ((fout=stfopen(name, openmode)) <= 0)
  952.         return ERROR;
  953.  
  954.     return OK;
  955. }
  956.  
  957. /*
  958.  * Putsec writes the n characters of buf to receive file fout.
  959.  *  If not in binary mode,  all characters
  960.  *  starting with CPMEOF are discarded.
  961.  */
  962. putsec(buf, n)
  963. unsigned char *buf;
  964. register int n;
  965. {
  966.     register unsigned char *p;
  967.  
  968.     if (Thisbinary)
  969.     {
  970.         for (p=buf; --n>=0; p++ )
  971.         {
  972.             if(stputc( *p, fout) < 0)
  973.             {
  974.                 fprintf(STDERR, "\r\nError while Writing file\n");
  975.                 return ERROR;
  976.             }
  977.         }
  978.     }
  979.     else
  980.     {
  981.         if (Eofseen)
  982.             return OK;
  983.  
  984.         for (p=buf; --n>=0; p++ )
  985.         {
  986.             if (*p == CPMEOF)
  987.             {
  988.                 Eofseen=TRUE;
  989.                 return OK;
  990.             }
  991.             if(*p == '\n')
  992.             {
  993.                 if(stputc('\r' ,fout) < 0)
  994.                 {
  995.                     fprintf(STDERR, "\r\nError while Writing file\n");
  996.                     return ERROR;
  997.                 }
  998.             }
  999.             if(stputc(*p ,fout) < 0)
  1000.             {
  1001.                 fprintf(STDERR,"\r\nError while Writing file\n");
  1002.                 return ERROR;
  1003.             }
  1004.         }
  1005.     }
  1006.  
  1007.     return OK;
  1008. }
  1009.  
  1010. /*
  1011.  * Log an error only if high verbose
  1012.  */
  1013. /*VARARGS1*/
  1014. llog(s,p,u)
  1015. char *s;
  1016. int p, u;
  1017. {
  1018.     if (Verbose < 3)
  1019.         return;
  1020. #ifdef RDEBUG
  1021.     fprintf(logf, "error %d: ", errors);
  1022.     fprintf(logf, s, p, u);
  1023. #endif
  1024.  
  1025.     fprintf(STDERR, "\nerror %d: ", errors);
  1026.     fprintf(STDERR, s, p, u);
  1027. }
  1028.  
  1029.  
  1030.  
  1031. #ifndef STANDALONE
  1032. /*
  1033.  * If called as rb use YMODEM protocol
  1034.  */
  1035. chkinvok(s)
  1036. char *s;
  1037. {
  1038.     Progname = s;
  1039.     if (s[0]=='r' && s[1]=='b')
  1040.         Nozmodem = TRUE;
  1041. }
  1042. #endif
  1043.  
  1044. /*
  1045.  * Initialize for Zmodem receive attempt, try to activate Zmodem sender
  1046.  *  Handles ZSINIT frame
  1047.  *  Return ZFILE if Zmodem filename received, -1 on error,
  1048.  *   ZCOMPL if transaction finished,  else 0
  1049.  */
  1050. tryz()
  1051. {
  1052.     register int n;
  1053.     register int cmdzack1flg;
  1054.  
  1055.     if (Nozmodem)        /* Check for "rb" program name */
  1056.         return 0;
  1057.  
  1058.  
  1059.     for (n=Zmodem?10:5; --n>=0; )
  1060.     {
  1061.         /* Set buffer length (0) and capability flags */
  1062.         stohdr(0L);
  1063.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK; /* of course we can break */
  1064.  
  1065.         zshhdr(tryzhdrtype, Txhdr);
  1066. /*        zshhdr(Badclose?ZFERR:ZRINIT, Txhdr); */
  1067. again:
  1068.         switch (zgethdr(Rxhdr, 0))
  1069.         {
  1070.         case ZRQINIT:
  1071.             continue;
  1072.         case ZEOF:
  1073.             continue;
  1074.         case TIMEOUT:
  1075.             continue;
  1076.         case ZFILE:
  1077.             zconv = Rxhdr[ZF0];
  1078.             zmanag = Rxhdr[ZF1];
  1079.             ztrans = Rxhdr[ZF2];
  1080.             tryzhdrtype = ZRINIT;
  1081.             Badclose = FALSE;
  1082.             if (zrdata(secbuf, KSIZE) == GOTCRCW)
  1083.                 return ZFILE;
  1084.             zshhdr(ZNAK, Txhdr);
  1085.             goto again;
  1086.         case ZSINIT:
  1087.             if (zrdata(Attn, ZATTNLEN) == GOTCRCW)
  1088.             {
  1089.                 zshhdr(ZACK, Txhdr);
  1090.                 goto again;
  1091.             }
  1092.             zshhdr(ZNAK, Txhdr);
  1093.             goto again;
  1094.         case ZFREECNT:
  1095.             stohdr(~0L);
  1096.             zshhdr(ZACK, Txhdr);
  1097.             goto again;
  1098.         case ZCOMMAND:
  1099.             cmdzack1flg = Rxhdr[ZF0];
  1100.             if (zrdata(secbuf, KSIZE) == GOTCRCW)
  1101.             {
  1102.                 if (cmdzack1flg & ZCACK1)
  1103.                     stohdr(0L);
  1104.                 else
  1105.                     stohdr((long)sys2(secbuf));
  1106.                 PURGELINE;    /* dump impatient questions */
  1107.                 do {
  1108.                     zshhdr(ZCOMPL, Txhdr);
  1109.                 }
  1110.                 while (++errors<10 && zgethdr(Rxhdr,1) != ZFIN);
  1111.                 ackbibi();
  1112.                 if (cmdzack1flg & ZCACK1)
  1113.                     exec2(secbuf);
  1114.                 return ZCOMPL;
  1115.             }
  1116.             zshhdr(ZNAK, Txhdr); goto again;
  1117.         case ZCOMPL:
  1118.             goto again;
  1119.         default:
  1120.             continue;
  1121.         case ZFIN:
  1122.             ackbibi(); return ZCOMPL;
  1123.         case ZCAN:
  1124.             return ERROR;
  1125.         }
  1126.     }
  1127.     return 0;
  1128. }
  1129.  
  1130. /*
  1131.  * Receive 1 or more files with ZMODEM protocol
  1132.  */
  1133. rzfiles()
  1134. {
  1135.     register int c;
  1136.  
  1137.     for (;;) {
  1138.         switch (c = rzfile()) {
  1139.         case ZEOF:
  1140.         case ZSKIP:
  1141.             switch (tryz()) {
  1142.             case ZCOMPL:
  1143.                 return OK;
  1144.             default:
  1145.                 return ERROR;
  1146.             case ZFILE:
  1147.                 break;
  1148.             }
  1149.             continue;
  1150.         default:
  1151.             return c;
  1152.         case ERROR:
  1153.             return ERROR;
  1154.         }
  1155.     }
  1156. }
  1157.  
  1158. /*
  1159.  * Receive a file with ZMODEM protocol
  1160.  *  Assumes file name frame is in secbuf
  1161.  */
  1162. rzfile()
  1163. {
  1164.     register int c, n;
  1165.     long rxbytes;
  1166.     extern void rd_time();
  1167.  
  1168.     Eofseen=FALSE;
  1169.     if (procheader(secbuf) == ERROR) {
  1170.         return (tryzhdrtype = ZSKIP);
  1171. /*        zshhdr(ZSKIP, Txhdr);
  1172.         return ZSKIP; */
  1173.     }
  1174.  
  1175.     n = 10; rxbytes = 0L;
  1176.  
  1177.     Supexec(rd_time);
  1178.     start_time = pr_time;
  1179.  
  1180.     for (;;)
  1181.     {
  1182.         stohdr(rxbytes);
  1183.         zshhdr(ZRPOS, Txhdr);
  1184. nxthdr:
  1185.         switch (c = zgethdr(Rxhdr, 0)) {
  1186.         default:
  1187.             vfile("rzfile: zgethdr returned %d", c);
  1188.             return ERROR;
  1189.         case ZNAK:
  1190.         case TIMEOUT:
  1191.             if ( --n < 0)
  1192.             {
  1193.                 vfile("rzfile: zgethdr returned %d", c);
  1194.                 return ERROR;
  1195.             }
  1196.         case ZFILE:
  1197.             zrdata(secbuf, KSIZE);
  1198.             continue;
  1199.         case ZEOF:
  1200.             /* ++jrb */
  1201.             if (rclhdr(Rxhdr) != rxbytes)
  1202.             {
  1203.                 /*
  1204.                      * Ignore eof if it's at wrong place - force
  1205.                      *  a timeout because the eof might have gone
  1206.                      *  out before we sent our zrpos.
  1207.                      */
  1208.  
  1209.                     errors = 0;  goto nxthdr;
  1210.             }
  1211. /* --jrb
  1212.             if (rclhdr(Rxhdr) != rxbytes)
  1213.             {
  1214.                 continue;
  1215.             }
  1216. -- */
  1217.             if (closeit(rxbytes))
  1218.             {
  1219.                 tryzhdrtype = ZFERR;
  1220.                 Badclose = TRUE;
  1221.                 vfile("rzfile: closeit returned <> 0");
  1222.                 return ERROR;
  1223.             }
  1224.             vfile("rzfile: normal EOF");
  1225.             return c;
  1226.         case ERROR:    /* Too much garbage in header search error */
  1227.             if ( --n < 0)
  1228.             {
  1229.                 vfile("rzfile: zgethdr returned %d", c);
  1230.                 return ERROR;
  1231.             }
  1232.             zmputs(Attn);
  1233.             continue;
  1234.         case ZDATA:
  1235.             n = 10;
  1236.             if (rclhdr(Rxhdr) != rxbytes)
  1237.             {
  1238.                 zmputs(Attn);
  1239.                 continue;
  1240.             }
  1241. moredata:
  1242.             switch (c = zrdata(secbuf, KSIZE))
  1243.             {
  1244.             case ZCAN:
  1245.                 vfile("rzfile: zgethdr returned %d", c);
  1246.                 return ERROR;
  1247.             case ERROR:    /* CRC error */
  1248.                 if ( --n < 0)
  1249.                 {
  1250.                     vfile("rzfile: zgethdr returned %d", c);
  1251.                     return ERROR;
  1252.                 }
  1253.                 zmputs(Attn);
  1254.                 continue;
  1255.             case TIMEOUT:
  1256.                 if ( --n < 0)
  1257.                 {
  1258.                     vfile("rzfile: zgethdr returned %d", c);
  1259.                     return ERROR;
  1260.                 }
  1261.                 continue;
  1262.             case GOTCRCW:
  1263.                 if(putsec(secbuf, Rxcount) == ERROR)
  1264.                     return ERROR;
  1265.                 rxbytes += Rxcount;
  1266.                 lreport(rxbytes);
  1267.                 stohdr(rxbytes);
  1268.                 zshhdr(ZACK, Txhdr);
  1269.                 goto nxthdr;
  1270.             case GOTCRCQ:
  1271.                 if(putsec(secbuf, Rxcount) == ERROR)
  1272.                     return ERROR;
  1273.                 rxbytes += Rxcount;
  1274.                 lreport(rxbytes);
  1275.                 stohdr(rxbytes);
  1276.                 zshhdr(ZACK, Txhdr);
  1277.                 goto moredata;
  1278.             case GOTCRCG:
  1279.                 if(putsec(secbuf, Rxcount) == ERROR)
  1280.                     return ERROR;
  1281.                 rxbytes += Rxcount;
  1282.                 lreport(rxbytes);
  1283.                 goto moredata;
  1284.             case GOTCRCE:
  1285.                 if(putsec(secbuf, Rxcount) == ERROR)
  1286.                     return ERROR;
  1287.                 rxbytes += Rxcount;
  1288.                 lreport(rxbytes);
  1289.                 goto nxthdr;
  1290.             }
  1291.         }
  1292.     }
  1293. }
  1294.  
  1295. /*
  1296.  * Send a string to the modem, processing for \336 (sleep 1 sec)
  1297.  *   and \335 (break signal)
  1298.  */
  1299. zmputs(s)
  1300. char *s;
  1301. {
  1302.     register int c;
  1303.  
  1304.     while (*s) {
  1305.         switch (c = *s++) {
  1306.         case '\336':
  1307.             stsleep(1); continue;
  1308.         case '\335':
  1309.             sendbrk(); continue;
  1310.         default:
  1311.             sendline(c);
  1312.         }
  1313.     }
  1314. }
  1315.  
  1316.  
  1317.  
  1318. /*
  1319.  * Close the receive dataset, return OK or ERROR
  1320.  */
  1321. closeit(rxbytes)
  1322. long rxbytes;
  1323. {
  1324.     unsigned int timep[2];
  1325.     long end_time;
  1326.     extern void rd_time();
  1327.  
  1328.     if (stfclose(fout) != 0) {
  1329.         fprintf(STDERR, "\r\nfile close ERROR\n");
  1330.         return ERROR;
  1331.     }
  1332.     fout = (-1);
  1333.  
  1334.     Supexec(rd_time);
  1335.     end_time = pr_time;
  1336.  
  1337.     if (Modtime) {
  1338.         unix2st(Modtime, &timep[0], &timep[1]);
  1339.         touch(Pathname, timep);
  1340.     }
  1341.  
  1342.     /* if it is read only by owner on remote, then it is set
  1343.      * to read only on the ST, all other file modes are
  1344.      * irrelevant.
  1345.      */
  1346.     if (Filemode)
  1347.     {
  1348.         unsigned int fmode;
  1349.  
  1350.         fmode = (unsigned int)(Filemode & 000777);
  1351.         if( ((fmode & 0200) == 0) && ((fmode & 0400) != 0) )
  1352.         {
  1353.             /* it is readonly by owner on the remote, so
  1354.              * make it read only on the ST too
  1355.              */
  1356.             Fattrib(Pathname, 1, 0x01);
  1357.         }
  1358.     }
  1359. #ifndef REMOTE
  1360.     if(rxbytes != 0L)
  1361.         fprintf(STDERR,"\n\n%s Closed\nTransfer Time %ld secs.\tfor %ld bytes\
  1362. \tApprox %ld cps\n\n", Pathname, (end_time - start_time)/200L, rxbytes,
  1363. rxbytes/((end_time - start_time)/200L));
  1364.     else
  1365.         fprintf(STDERR,"\n\n%s Closed\n\n", Pathname);
  1366. #endif
  1367.     lsct = 1;
  1368.     return OK;
  1369. }
  1370.  
  1371. /*
  1372.  * Ack a ZFIN packet, let byegones be byegones
  1373.  */
  1374. ackbibi()
  1375. {
  1376.     register int n;
  1377.  
  1378.     vfile("ackbibi:");
  1379.     Readnum = 1;
  1380.     stohdr(0L);
  1381.     for (n=4; --n>=0; )
  1382.     {
  1383.         zshhdr(ZFIN, Txhdr);
  1384.         for (;;) {
  1385.             switch (readline(100))
  1386.             {
  1387.             case 'O':
  1388.                 readline(1);    /* Discard 2nd 'O' */
  1389.                 /* ***** FALL THRU TO ***** */
  1390.             case TIMEOUT:
  1391.                 vfile("ackbibi complete");
  1392.                 return;
  1393.             default:
  1394.                 break;
  1395.             }
  1396.         }
  1397.     }
  1398. }
  1399.  
  1400.  
  1401. /*
  1402.  * Strip leading ! if present, do shell escape. 
  1403.  */
  1404. sys2(s)
  1405. register char *s;
  1406. {
  1407.     if (*s == '!')
  1408.         ++s;
  1409.     return stsystem(s);
  1410. }
  1411. /*
  1412.  * Strip leading ! if present, do exec.
  1413.  */
  1414. exec2(s)
  1415. char *s;
  1416. {
  1417. /** Are you kidding
  1418.     if (*s == '!')
  1419.         ++s;
  1420.     mode(0);
  1421.     execl("/bin/sh", "sh", "-c", s); 
  1422. **/
  1423. }
  1424.  
  1425. /*
  1426.  * Touch a file
  1427.  */
  1428. #ifndef MANX
  1429. #undef Fdatime        /* There exist brain damaged versions of osbind.h */
  1430. #define    Fdatime(a,b,c)    gemdos(0x57,a,b,c)
  1431. #endif /* MANX has its _Gemdos stuff */
  1432.  
  1433. touch(name, timep)
  1434. char *name;
  1435. unsigned int *timep;
  1436. {
  1437.     register int handl;
  1438.  
  1439.     if((handl = Fopen(name, 0)) < 0)
  1440.     {
  1441. #ifndef REMOTE
  1442.         fprintf(STDERR,"*WARNING* Could not set file modification time for %s\n",
  1443.             name);
  1444. #endif
  1445.         return;
  1446.     }
  1447.  
  1448.  
  1449.     Fdatime(timep, handl, 1);
  1450.     Fclose(handl);
  1451. }
  1452.  
  1453. /* -eof- */
  1454.